local meta = require("dpkt.meta")
local utils = require("dpkt.utils")
local IP = {
    -- Type of service (ip_tos), RFC 1349 ("obsoleted by RFC 2474")
    IP_TOS_DEFAULT = 0x00,  -- default
    IP_TOS_LOWDELAY = 0x10,  -- low delay
    IP_TOS_THROUGHPUT = 0x08,  -- high throughput
    IP_TOS_RELIABILITY = 0x04,  -- high reliability
    IP_TOS_LOWCOST = 0x02,  -- low monetary cost - XXX
    IP_TOS_ECT = 0x02,  -- ECN-capable transport
    IP_TOS_CE = 0x01,  -- congestion experienced

    -- IP precedence (high 3 bits of ip_tos), hopefully unused
    IP_TOS_PREC_ROUTINE = 0x00,
    IP_TOS_PREC_PRIORITY = 0x20,
    IP_TOS_PREC_IMMEDIATE = 0x40,
    IP_TOS_PREC_FLASH = 0x60,
    IP_TOS_PREC_FLASHOVERRIDE = 0x80,
    IP_TOS_PREC_CRITIC_ECP = 0xa0,
    IP_TOS_PREC_INTERNETCONTROL = 0xc0,
    IP_TOS_PREC_NETCONTROL = 0xe0,

    -- Fragmentation flags (ip_off)
    IP_RF = 0x8000,  -- reserved
    IP_DF = 0x4000,  -- don't fragment
    IP_MF = 0x2000,  -- more fragments (not last frag)
    IP_OFFMASK = 0x1fff,  -- mask for fragment offset

    -- Time-to-live (ip_ttl), seconds
    IP_TTL_DEFAULT = 64,  -- default ttl, RFC 1122, RFC 1340
    IP_TTL_MAX = 255,  -- maximum ttl

    -- Protocol (ip_p)
    IP_PROTO_IP = 0,  -- dummy for IP
    IP_PROTO_HOPOPTS = IP_PROTO_IP,  -- IPv6 hop-by-hop options
    IP_PROTO_ICMP = 1,  -- ICMP
    IP_PROTO_IGMP = 2,  -- IGMP
    IP_PROTO_GGP = 3,  -- gateway-gateway protocol
    IP_PROTO_IPIP = 4,  -- IP in IP
    IP_PROTO_ST = 5,  -- ST datagram mode
    IP_PROTO_TCP = 6,  -- TCP
    IP_PROTO_CBT = 7,  -- CBT
    IP_PROTO_EGP = 8,  -- exterior gateway protocol
    IP_PROTO_IGP = 9,  -- interior gateway protocol
    IP_PROTO_BBNRCC = 10,  -- BBN RCC monitoring
    IP_PROTO_NVP = 11,  -- Network Voice Protocol
    IP_PROTO_PUP = 12,  -- PARC universal packet
    IP_PROTO_ARGUS = 13,  -- ARGUS
    IP_PROTO_EMCON = 14,  -- EMCON
    IP_PROTO_XNET = 15,  -- Cross Net Debugger
    IP_PROTO_CHAOS = 16,  -- Chaos
    IP_PROTO_UDP = 17,  -- UDP
    IP_PROTO_MUX = 18,  -- multiplexing
    IP_PROTO_DCNMEAS = 19,  -- DCN measurement
    IP_PROTO_HMP = 20,  -- Host Monitoring Protocol
    IP_PROTO_PRM = 21,  -- Packet Radio Measurement
    IP_PROTO_IDP = 22,  -- Xerox NS IDP
    IP_PROTO_TRUNK1 = 23,  -- Trunk-1
    IP_PROTO_TRUNK2 = 24,  -- Trunk-2
    IP_PROTO_LEAF1 = 25,  -- Leaf-1
    IP_PROTO_LEAF2 = 26,  -- Leaf-2
    IP_PROTO_RDP = 27,  -- "Reliable Datagram" proto
    IP_PROTO_IRTP = 28,  -- Inet Reliable Transaction
    IP_PROTO_TP = 29,  -- ISO TP class 4
    IP_PROTO_NETBLT = 30,  -- Bulk Data Transfer
    IP_PROTO_MFPNSP = 31,  -- MFE Network Services
    IP_PROTO_MERITINP = 32,  -- Merit Internodal Protocol
    IP_PROTO_SEP = 33,  -- Sequential Exchange proto
    IP_PROTO_3PC = 34,  -- Third Party Connect proto
    IP_PROTO_IDPR = 35,  -- Interdomain Policy Route
    IP_PROTO_XTP = 36,  -- Xpress Transfer Protocol
    IP_PROTO_DDP = 37,  -- Datagram Delivery Proto
    IP_PROTO_CMTP = 38,  -- IDPR Ctrl Message Trans
    IP_PROTO_TPPP = 39,  -- TP++ Transport Protocol
    IP_PROTO_IL = 40,  -- IL Transport Protocol
    IP_PROTO_IP6 = 41,  -- IPv6
    IP_PROTO_SDRP = 42,  -- Source Demand Routing
    IP_PROTO_ROUTING = 43,  -- IPv6 routing header
    IP_PROTO_FRAGMENT = 44,  -- IPv6 fragmentation header
    IP_PROTO_RSVP = 46,  -- Reservation protocol
    IP_PROTO_GRE = 47,  -- General Routing Encap
    IP_PROTO_MHRP = 48,  -- Mobile Host Routing
    IP_PROTO_ENA = 49,  -- ENA
    IP_PROTO_ESP = 50,  -- Encap Security Payload
    IP_PROTO_AH = 51,  -- Authentication Header
    IP_PROTO_INLSP = 52,  -- Integated Net Layer Sec
    IP_PROTO_SWIPE = 53,  -- SWIPE
    IP_PROTO_NARP = 54,  -- NBMA Address Resolution
    IP_PROTO_MOBILE = 55,  -- Mobile IP, RFC 2004
    IP_PROTO_TLSP = 56,  -- Transport Layer Security
    IP_PROTO_SKIP = 57,  -- SKIP
    IP_PROTO_ICMP6 = 58,  -- ICMP for IPv6
    IP_PROTO_NONE = 59,  -- IPv6 no next header
    IP_PROTO_DSTOPTS = 60,  -- IPv6 destination options
    IP_PROTO_ANYHOST = 61,  -- any host internal proto
    IP_PROTO_CFTP = 62,  -- CFTP
    IP_PROTO_ANYNET = 63,  -- any local network
    IP_PROTO_EXPAK = 64,  -- SATNET and Backroom EXPAK
    IP_PROTO_KRYPTOLAN = 65,  -- Kryptolan
    IP_PROTO_RVD = 66,  -- MIT Remote Virtual Disk
    IP_PROTO_IPPC = 67,  -- Inet Pluribus Packet Core
    IP_PROTO_DISTFS = 68,  -- any distributed fs
    IP_PROTO_SATMON = 69,  -- SATNET Monitoring
    IP_PROTO_VISA = 70,  -- VISA Protocol
    IP_PROTO_IPCV = 71,  -- Inet Packet Core Utility
    IP_PROTO_CPNX = 72,  -- Comp Proto Net Executive
    IP_PROTO_CPHB = 73,  -- Comp Protocol Heart Beat
    IP_PROTO_WSN = 74,  -- Wang Span Network
    IP_PROTO_PVP = 75,  -- Packet Video Protocol
    IP_PROTO_BRSATMON = 76,  -- Backroom SATNET Monitor
    IP_PROTO_SUNND = 77,  -- SUN ND Protocol
    IP_PROTO_WBMON = 78,  -- WIDEBAND Monitoring
    IP_PROTO_WBEXPAK = 79,  -- WIDEBAND EXPAK
    IP_PROTO_EON = 80,  -- ISO CNLP
    IP_PROTO_VMTP = 81,  -- Versatile Msg Transport
    IP_PROTO_SVMTP = 82,  -- Secure VMTP
    IP_PROTO_VINES = 83,  -- VINES
    IP_PROTO_TTP = 84,  -- TTP
    IP_PROTO_NSFIGP = 85,  -- NSFNET-IGP
    IP_PROTO_DGP = 86,  -- Dissimilar Gateway Proto
    IP_PROTO_TCF = 87,  -- TCF
    IP_PROTO_EIGRP = 88,  -- EIGRP
    IP_PROTO_OSPF = 89,  -- Open Shortest Path First
    IP_PROTO_SPRITERPC = 90,  -- Sprite RPC Protocol
    IP_PROTO_LARP = 91,  -- Locus Address Resolution
    IP_PROTO_MTP = 92,  -- Multicast Transport Proto
    IP_PROTO_AX25 = 93,  -- AX.25 Frames
    IP_PROTO_IPIPENCAP = 94,  -- yet-another IP encap
    IP_PROTO_MICP = 95,  -- Mobile Internet Ctrl
    IP_PROTO_SCCSP = 96,  -- Semaphore Comm Sec Proto
    IP_PROTO_ETHERIP = 97,  -- Ethernet in IPv4
    IP_PROTO_ENCAP = 98,  -- encapsulation header
    IP_PROTO_ANYENC = 99,  -- private encryption scheme
    IP_PROTO_GMTP = 100,  -- GMTP
    IP_PROTO_IFMP = 101,  -- Ipsilon Flow Mgmt Proto
    IP_PROTO_PNNI = 102,  -- PNNI over IP
    IP_PROTO_PIM = 103,  -- Protocol Indep Multicast
    IP_PROTO_ARIS = 104,  -- ARIS
    IP_PROTO_SCPS = 105,  -- SCPS
    IP_PROTO_QNX = 106,  -- QNX
    IP_PROTO_AN = 107,  -- Active Networks
    IP_PROTO_IPCOMP = 108,  -- IP Payload Compression
    IP_PROTO_SNP = 109,  -- Sitara Networks Protocol
    IP_PROTO_COMPAQPEER = 110,  -- Compaq Peer Protocol
    IP_PROTO_IPXIP = 111,  -- IPX in IP
    IP_PROTO_VRRP = 112,  -- Virtual Router Redundancy
    IP_PROTO_PGM = 113,  -- PGM Reliable Transport
    IP_PROTO_ANY0HOP = 114,  -- 0-hop protocol
    IP_PROTO_L2TP = 115,  -- Layer 2 Tunneling Proto
    IP_PROTO_DDX = 116,  -- D-II Data Exchange (DDX)
    IP_PROTO_IATP = 117,  -- Interactive Agent Xfer
    IP_PROTO_STP = 118,  -- Schedule Transfer Proto
    IP_PROTO_SRP = 119,  -- SpectraLink Radio Proto
    IP_PROTO_UTI = 120,  -- UTI
    IP_PROTO_SMP = 121,  -- Simple Message Protocol
    IP_PROTO_SM = 122,  -- SM
    IP_PROTO_PTP = 123,  -- Performance Transparency
    IP_PROTO_ISIS = 124,  -- ISIS over IPv4
    IP_PROTO_FIRE = 125,  -- FIRE
    IP_PROTO_CRTP = 126,  -- Combat Radio Transport
    IP_PROTO_CRUDP = 127,  -- Combat Radio UDP
    IP_PROTO_SSCOPMCE = 128,  -- SSCOPMCE
    IP_PROTO_IPLT = 129,  -- IPLT
    IP_PROTO_SPS = 130,  -- Secure Packet Shield
    IP_PROTO_PIPE = 131,  -- Private IP Encap in IP
    IP_PROTO_SCTP = 132,  -- Stream Ctrl Transmission
    IP_PROTO_FC = 133,  -- Fibre Channel
    IP_PROTO_RSVPIGN = 134,  -- RSVP-E2E-IGNORE
    IP_PROTO_RAW = 255,  -- Raw IP packets
    IP_PROTO_RESERVED = IP_PROTO_RAW,  -- Reserved
    IP_PROTO_MAX = 255
}
setmetatable(IP, meta)

function IP:init(buf)
    local o = {__buf = buf}
    setmetatable(o, {__index = self, __name = 'IP'})
    o:unpack()
    return o
end

function IP:unpack()
    local _v_hl, tos, len, id, off, ttl, proto, sum, src, dst = string.unpack('I1I1I2I2I2I1I1I2I4I4', self.__buf)
    self.ver = (_v_hl >> 4) & 0x0f
    self.hdrlen = _v_hl & 0x0f
    self.tos = tos
    self.len = utils.ntohs(len)
    self.id = utils.ntohs(id)
    self.off = utils.ntohs(off)
    self.ttl = ttl
    self.proto = proto
    self.sum = utils.ntohs(sum)
    self.src = utils.ip2str(src)
    self.dst = utils.ip2str(dst)
    self.data = string.sub(self.__buf, self.hdrlen * 4 + 1)
end

function IP:pack()
end

return IP
